<?php

namespace app\admin\logic;

use app\admin\model\Course;
use app\admin\model\CoursePaper;
use app\admin\model\CourseQuestion;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\IOFactory;

/**
 * 生成试卷电子档
 */
class GeneratePaperDocument
{
    /**
     * 执行任务
     * @param int $paperId 试卷ID
     * @param int $scene 应用场景(1:练习模式,2:背题模式)
     * @return array
     * @throws \Exception
     */
    public function invoke($paperId, $scene)
    {
        // 控制开关：是否生成答案和解析
        $showAnswerAndExplanation = ($scene == 2); // 背题模式生成答案和解析，练习模式不生成
        
        // 控制开关：是否生成页眉
        $enableHeader = false; // 设置为false可关闭页眉生成
        
        // 查询试卷
        $paperModel = new CoursePaper();
        $paper = $paperModel->get($paperId);
        if (!$paper) {
            throw new \Exception('试卷不存在');
        }

        // 查询课程信息
        $courseModel = new Course();
        $course = $courseModel->find($paper->course_id);
        if (!$course) {
            throw new \Exception('课程不存在');
        }

        // 生成试卷名称
        $paperName = $course->name;
        if($course['code']){
            $paperName .= '【' . $course['code'].'】';
        }
        $paperName .= $paper['name'];

        // 查询当前试卷的题目
        $questionModel = new \app\common\model\CourseQuestion();
        $questions = $questionModel->where('extend_id', $paper->id)->select();
        if (!$questions) {
            throw new \Exception('试卷题目为空');
        }

        // 为每个试卷创建独立的Word文档
        $phpWord = new PhpWord();

        // 设置文档默认字体和样式
        $phpWord->setDefaultFontName('宋体'); // 使用宋体作为默认字体
        $phpWord->setDefaultFontSize(12);

        // 添加一个章节
        $section = $phpWord->addSection();
        
        // 根据开关决定是否添加页眉
        if ($enableHeader) {
            $header = $section->addHeader();
            $header->addText('翰林刷题小程序', ['name' => '宋体', 'size' => 12, 'bold' => true], ['alignment' => 'center']);
        }

        // 添加试卷标题（清洗后）
        $section->addText($this->cleanTextForXml($paperName), ['bold' => true, 'size' => 18, 'name' => '黑体'], ['alignment' => 'center']);
        $section->addTextBreak(2); // 标题后增加更多间距

        // 添加题目
        $totalQuestions = count($questions);
        
        foreach ($questions as $index => $question) {
            $questionNumber = $index + 1;
            
            $questionTitle = $questionNumber . '、' . $question->question_name;

            // 清理HTML标签并处理特殊字符
            $questionTitle = strip_tags($questionTitle);
            $questionTitle = htmlspecialchars_decode($questionTitle, ENT_QUOTES);
            // 进一步清理特殊字符，确保符合XML标准
            $questionTitle = $this->cleanTextForXml($questionTitle);

            $section->addText($questionTitle, ['size' => 14, 'name' => '宋体', 'bold' => true]);

            // 解析question_data字段
            if (!empty($question->question_data)) {
                $questionData = json_decode($question->question_data, true);
                if (json_last_error() !== JSON_ERROR_NONE) {
                    // JSON解析失败，记录错误但继续处理
                    $questionData = null;
                }
                if ($questionData) {
                    // 处理选项（单选、多选、判断题统一处理）
                    if (in_array($question->question_type, [1, 2, 3])) { // 单选、多选、判断题
                        if (isset($questionData['answerOption']) && is_array($questionData['answerOption']) && !empty($questionData['answerOption'])) {
                            $options = $questionData['answerOption'];
                            $section->addTextBreak(1); // 选项列表前增加间距
                            foreach ($options as $key => $option) {
                                // 跳过空选项，但继续处理其他选项
                                if (empty($option) || trim($option) === '') {
                                    continue;
                                }
                                // 清理HTML标签并处理特殊字符
                                $option = strip_tags($option);
                                $option = htmlspecialchars_decode($option, ENT_QUOTES);
                                // 进一步清理特殊字符，确保符合XML标准
                                $option = $this->cleanTextForXml($option);
                                $section->addText('    ' . $key . '. ' . $option, ['size' => 13, 'name' => '宋体']);
                                $section->addTextBreak(1); // 每个选项后增加1行间距
                            }
                            $section->addTextBreak(1);
                        }
                    }

                    // 添加正确答案（清洗后）
                    if ($showAnswerAndExplanation && isset($questionData['correctOption'])) {
                        $correctText = $this->cleanTextForXml(htmlspecialchars_decode(strip_tags((string)$questionData['correctOption']), ENT_QUOTES));
                        $section->addText('正确答案：' . $correctText, ['bold' => true, 'size' => 14, 'color' => 'FF0000', 'name' => '宋体']);
                        $section->addTextBreak(1);
                    }

                    // 添加解析（清洗后）
                    if ($showAnswerAndExplanation) {
                        $explainText = '';
                        if (isset($questionData['aiExplanation']) && !empty($questionData['aiExplanation'])) {
                            $explainText = $questionData['aiExplanation'];
                        } elseif (isset($questionData['explanation']) && !empty($questionData['explanation'])) {
                            $explainText = $questionData['explanation'];
                        }
                        if ($explainText !== '') {
                            $explainText = $this->cleanTextForXml(htmlspecialchars_decode(strip_tags((string)$explainText), ENT_QUOTES));
                            $section->addText('解析：' . $explainText, ['size' => 12, 'name' => '宋体', 'italic' => false]);
                        }
                    }

                    // 每道题之间添加明显的分隔线
                    $section->addTextBreak(1);
                    $section->addText('─────────────────────────────', ['size' => 10, 'name' => '宋体', 'color' => 'CCCCCC']);
                    $section->addTextBreak(1);
                }
            }

            $section->addTextBreak(1);
        }

        // 添加参考答案部分（即使$showAnswerAndExplanation为false也生成）
        $section = $phpWord->addSection();
        $section->addText('参考答案', ['bold' => true, 'size' => 16, 'name' => '黑体'], ['alignment' => 'center']);
        $section->addTextBreak(2);
        
        foreach ($questions as $index => $question) {
            $questionNumber = $index + 1;
            if (!empty($question->question_data)) {
                $questionData = json_decode($question->question_data, true);
                if (isset($questionData['correctOption'])) {
                    $correctText = $this->cleanTextForXml(htmlspecialchars_decode(strip_tags((string)$questionData['correctOption']), ENT_QUOTES));
                    $section->addText($questionNumber . '. ' . $correctText, ['size' => 14, 'name' => '宋体']);
                    $section->addTextBreak(1);
                }
            }
        }
        
        // 保存Word文档
        // 处理文件名中的特殊字符，确保文件系统兼容性
        $safePaperName = preg_replace('/[^a-zA-Z0-9\-_\x{4e00}-\x{9fa5}]/u', '_', $paperName);
        // 保存文档
        $filename = $safePaperName . '_' . date('YmdHis') . '.docx';
        $filepath = ROOT_PATH . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . $filename;
        
        // 获取请求域名
        $domain = request()->domain();
        $fileUrl = $domain.'/uploads/' . $filename;
        try {
            $objWriter = IOFactory::createWriter($phpWord, 'Word2007');
            $objWriter->save($filepath);
            
            // 验证文件是否真正保存成功
            if (!file_exists($filepath)) {
                throw new \Exception('文档保存失败');
            } elseif (filesize($filepath) == 0) {
                throw new \Exception('文档保存失败');
            }
            
            return ['code' => 1, 'msg' => '文档生成成功', 'data' => ['filepath' => $filepath, 'filename' => $filename, 'fileUrl' => $fileUrl]];
        } catch (\Exception $e) {
            throw new \Exception('文档保存失败：' . $e->getMessage());
        }
    }

    /**
     * 清理文本中的特殊字符，确保符合XML标准
     * @param string $text
     * @return string
     */
    private function cleanTextForXml($text)
    {
        // 移除或替换可能导致XML解析错误的字符
        $text = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $text);
        // 替换特殊HTML实体
        $text = str_replace(['&nbsp;', '&mdash;', '&ndash;'], [' ', '—', '–'], $text);
        return $text;
    }
}